﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SimpleRest.Core.Extensions.Documentation;
using SimpleRest.Core.Extensions.OAuth.Exceptions;

namespace SimpleRest.Core.Extensions.OAuth
{
    /// <summary>
    /// Authorization service needed to authorize protected resources and to create authorization tokens for consumers.
    /// http://tools.ietf.org/html/rfc6749#section-5.2
    /// </summary>
    [GeneralDescription("Create an authorization code indicating a successful log in.")]
    [LinkDescription("http://tools.ietf.org/html/rfc6749", Description = "oAuth RFC 6749, issued October 2012.")]
    public abstract class AuthorizationServiceBase : ServiceBase, IAuthorizationAuthority
    {
        [GeneralDescription("Create an authorization code by providing appropriate oAuth 2.0 request parameters.  Upon submission of a successful request this endpoint will respond with a 302 redirect to the appropriate redirect_url with the appropriate response parameters contained within the redirect url provided.")]
        [ParameterDescription("response_type", typeof(string), false, Description = "Located in the uri, this field indicates the type of authorization request that should be executed.  Possible response_type values include: code and token.")]
        [ParameterDescription("client_id", typeof(string), false, Description = "Located in the uri, this field should contain the client_id issued by this system.")]
        [ParameterDescription("redirect_uri", typeof(string), true, Description = "Located in the uri, this field should contain the absolute uri that should be redirected to upon execution of a successful request.")]
        [ParameterDescription("scope", typeof(string[]), true, Description = "Located in the uri, this field should contain the scope of the request.  This value should contain a list of space-delimited, case-sensitive strings.  The strings are defined by the authorization server owned by this system.")]
        [ParameterDescription("state", typeof(string), true, Description = "Located in the uri, this field is recommended but not required.  This value should be an opaque value used by the client to maintain the state between the request and the callback.  Upon execution of a successful request the response should contain this value which is used to help for preventing cross-site request forgery.")]
        [LinkDescription("http://tools.ietf.org/html/rfc6749#section-3.3", Description = "Scope")]
        [LinkDescription("http://tools.ietf.org/html/rfc6749#section-4.1.1", Description = "Authorization Request: code")]
        [LinkDescription("http://tools.ietf.org/html/rfc6749#section-4.2.1", Description = "Authorization Request: token")]
        [StatusCodeDescription(ErrorCode = "access_denied", Description = "Access denied.", StatusCode = System.Net.HttpStatusCode.Unauthorized)]
        [StatusCodeDescription(ErrorCode = "invalid_scope", Description = "Scope value was received and is not supported.", StatusCode = System.Net.HttpStatusCode.BadRequest)]
        [StatusCodeDescription(ErrorCode = "server_error", Description = "An internal server has occured.", StatusCode = System.Net.HttpStatusCode.InternalServerError)]
        [StatusCodeDescription(ErrorCode = "temporarily_unavailable", Description = "Service is temporarily unavailable.", StatusCode = System.Net.HttpStatusCode.ServiceUnavailable)]
        [StatusCodeDescription(ErrorCode = "unauthorized_client", Description = "Requesting client is not authorized.", StatusCode = System.Net.HttpStatusCode.Unauthorized)]
        [StatusCodeDescription(ErrorCode = "unsupported_response_type", Description = "response_type provided is not supported", StatusCode = System.Net.HttpStatusCode.BadRequest)]
        [WebGet(UriTemplate = "?response_type={responseType}&client_id={clientId}&redirect_uri={redirectUri}&scope={scope}&state={state}")]
        public OperationResponse Authorize(string responseType, string clientId, string redirectUri, string scope, string state)
        {
            string error = "";
            string errorUri = null;
            string errorDescription = "";

            if (string.IsNullOrEmpty(redirectUri))
                return new OperationResponse(System.Net.HttpStatusCode.BadRequest);

            if (string.IsNullOrEmpty(responseType) ||
                string.IsNullOrEmpty(clientId) ||
                base.Request.Uri.ToLower().Contains(redirectUri.Replace("http://", "").Replace("https://", "").ToLower()))
            {
                error = "access_denied";
                errorDescription = new AccessDeniedException().Message;
            }
            else
            {
                try
                {
                    string code = this.CreateAuthorizationCode(new AuthorizationRequest(responseType, clientId, redirectUri, scope, state));

                    string url = redirectUri.TrimEnd(new char[] { '/', '\\' }) + string.Format("?code={0}", code);
                    if (!string.IsNullOrEmpty(state))
                        url += string.Format("state={0}", state);

                    return OperationResponse.Redirect(url);
                }
                catch (AccessDeniedException adEx)
                {
                    error = "access_denied";
                    if (!string.IsNullOrEmpty(adEx.ErrorUri))
                        errorUri = adEx.ErrorUri;
                    errorDescription = adEx.Message;
                }
                catch (InvalidScopeException isEx)
                {
                    error = "invalid_scope";
                    if (!string.IsNullOrEmpty(isEx.ErrorUri))
                        errorUri = isEx.ErrorUri;
                    errorDescription = isEx.Message;
                }
                catch (ServerErrorException seEx)
                {
                    error = "server_error";
                    if (!string.IsNullOrEmpty(seEx.ErrorUri))
                        errorUri = seEx.ErrorUri;
                    errorDescription = seEx.Message;
                }
                catch (TemporarilyUnavailableException tuEx)
                {
                    error = "temporarily_unavailable";
                    if (!string.IsNullOrEmpty(tuEx.ErrorUri))
                        errorUri = tuEx.ErrorUri;
                    errorDescription = tuEx.Message;
                }
                catch (UnAuthorizedClientException uacEx)
                {
                    error = "unauthorized_client";
                    if (!string.IsNullOrEmpty(uacEx.ErrorUri))
                        errorUri = uacEx.ErrorUri;
                    errorDescription = uacEx.Message;
                }
                catch (UnsupportedResponseTypeException urtEx)
                {
                    error = "unsupported_response_type";
                    if (!string.IsNullOrEmpty(urtEx.ErrorUri))
                        errorUri = urtEx.ErrorUri;
                    errorDescription = urtEx.Message;
                }
                catch (Exception ex)
                {
                    error = "server_error";
                    errorDescription = new ServerErrorException().Message;
                }
            }

            string errorUriTemplate = redirectUri.TrimEnd(new char[] { '/', '\\' }) + string.Format("?error={0}&error_description={1}", error, errorDescription);
            if (!string.IsNullOrEmpty(errorUri))
                errorUriTemplate += string.Format("&error_uri={0}", errorUri);

            return OperationResponse.Redirect(errorUriTemplate);
        }

        public virtual string CreateAuthorizationCode(AuthorizationRequest authorizeRequest)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Resolve authority of a request from a passed in MAC token.  MAC token RFC can be located here http://tools.ietf.org/html/rfc6750
        /// </summary>
        /// <param name="bearerToken"></param>
        /// <param name="protectedResource"></param>
        /// <param name="targetOperation"></param>
        /// <returns></returns>
        public virtual bool IsAuthorized(BearerToken bearerToken, string protectedResource, Operation targetOperation)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Resolve authority of a request from a passed in Bearer token.  The bearer token value should contain the access token
        /// given to a consumer in a prior request.
        /// </summary>
        /// <param name="token"></param>
        /// <param name="protectedResource"></param>
        /// <param name="targetOperation"></param>
        /// <returns></returns>
        public virtual bool IsAuthorized(MacToken token, string protectedResource, Operation targetOperation)
        {
            throw new NotImplementedException();
        }
    }
}
